#include "stdafx.h"
#include "gp_Trsf2d.h"
#include "gp.h"
#include "gp_Ax2d.h"
#include "gp_Ax22d.h"
#include "gp_Pnt2d.h"
#include "gp_Trsf2d.h"
#include "gp_Vec2d.h"
#include "gp_Elips2d.h"

void gp_Elips2d::Coefficients (double& A, 
	double& B, 
	double& C, 
	double& D, 
	double& E, 
	double& F) const 
{
	double DMin = minorRadius * minorRadius;
	double DMaj = majorRadius * majorRadius;
	if (DMin <= gp::Resolution() && DMaj <= gp::Resolution()) {
		A = B = C = D = E = F = 0.0;
	}
	else {
		gp_Trsf2d T;
		T.SetTransformation (pos.XAxis());
		double T11 = T.Value (1, 1);
		double T12 = T.Value (1, 2);
		double T13 = T.Value (1, 3);
		if (DMin <= gp::Resolution()) {
			A = T11 * T11;    B = T12 * T12;   C = T11 * T12;
			D = T11 * T13;    E = T12 * T13;   F = T13 * T13 - DMaj;
		}
		else {
			double T21 = T.Value (2, 1);
			double T22 = T.Value (2, 2);
			double T23 = T.Value (2, 3);
			A = (T11 * T11 / DMaj) + (T21 * T21 / DMin);
			B = (T12 * T12 / DMaj) + (T22 * T22 / DMin);
			C = (T11 * T12 / DMaj) + (T21 * T22 / DMin);
			D = (T11 * T13 / DMaj) + (T21 * T23 / DMin);
			E = (T12 * T13 / DMaj) + (T22 * T23 / DMin);
			F = (T13 * T13 / DMaj) + (T23 * T23 / DMin) - 1.0;
		}
	}
}

void gp_Elips2d::Mirror (const gp_Pnt2d& P)
{ pos.Mirror(P); }

gp_Elips2d gp_Elips2d::Mirrored (const gp_Pnt2d& P) const  
{
	gp_Elips2d E = *this;
	E.pos.Mirror (P);
	return E; 
}

void gp_Elips2d::Mirror (const gp_Ax2d& A)
{ pos.Mirror(A); }

gp_Elips2d gp_Elips2d::Mirrored (const gp_Ax2d& A) const  
{
	gp_Elips2d E = *this;
	E.pos.Mirror (A);
	return E; 
}
 gp_Elips2d::gp_Elips2d() :
majorRadius(DBL_MAX),
minorRadius(DBL_MIN)
{ }

 gp_Elips2d::gp_Elips2d (const gp_Ax2d& MajorAxis, 
			       const double MajorRadius, 
			       const double MinorRadius,
			       const bool Sense) :  
			       majorRadius(MajorRadius), 
			       minorRadius(MinorRadius) 
{ 
  pos = gp_Ax22d(MajorAxis,Sense);
  Standard_ConstructionError_Raise_if
  (MinorRadius < 0.0 || MajorRadius < MinorRadius, "");
}

 gp_Elips2d::gp_Elips2d (const gp_Ax22d& A, 
			       const double MajorRadius, 
			       const double MinorRadius) :  
			       pos(A), 
			       majorRadius(MajorRadius), 
			       minorRadius(MinorRadius) 
{ 
  Standard_ConstructionError_Raise_if
  (MinorRadius < 0.0 || MajorRadius < MinorRadius, "");
}

 void gp_Elips2d::SetLocation (const gp_Pnt2d& P)
{  pos.SetLocation(P);}

 void gp_Elips2d::SetMajorRadius (const double MajorRadius)
{ 
  majorRadius = MajorRadius;
}

 void gp_Elips2d::SetMinorRadius (const double MinorRadius)
{ 
	 Standard_ConstructionError_Raise_if
	 (MinorRadius < 0.0 || majorRadius < MinorRadius, "");
  minorRadius = MinorRadius;
}

 void gp_Elips2d::SetXAxis (const gp_Ax2d& A)
{ pos.SetXAxis(A); }

 void gp_Elips2d::SetAxis (const gp_Ax22d& A)
{ pos.SetAxis(A); }

 void gp_Elips2d::SetYAxis (const gp_Ax2d& A)
{  pos.SetYAxis(A); }

  double gp_Elips2d::Area() const
{ return M_PI * majorRadius * minorRadius; }

 gp_Ax2d gp_Elips2d::Directrix1() const
{
  double E = Eccentricity();
  Standard_ConstructionError_Raise_if(E <= gp::Resolution(), "");
  gp_XY Orig = pos.XDirection().XY();
  Orig.Multiply (majorRadius/E);
  Orig.Add (pos.Location().XY());
  return gp_Ax2d (gp_Pnt2d(Orig),gp_Dir2d (pos.YDirection()));
}

 gp_Ax2d gp_Elips2d::Directrix2() const
{
  double E = Eccentricity();
  Standard_ConstructionError_Raise_if(E <= gp::Resolution(), "");
  gp_XY Orig = pos.XDirection().XY();
  Orig.Multiply (-majorRadius/E);
  Orig.Add (pos.Location().XY());
  return gp_Ax2d (gp_Pnt2d(Orig),gp_Dir2d (pos.YDirection()));
}

 double gp_Elips2d::Eccentricity() const
{
  if (majorRadius == 0.0) {  return 0.0; }
  else {
    return sqrt(majorRadius * majorRadius - 
		minorRadius * minorRadius) / majorRadius;
  }
}

 double gp_Elips2d::Focal() const
{
  return 2.0 * sqrt(majorRadius * majorRadius -
		    minorRadius * minorRadius);
}

 gp_Pnt2d gp_Elips2d::Focus1() const
{
  double C = sqrt(majorRadius * majorRadius -
			 minorRadius * minorRadius);
  const gp_Pnt2d& PP = pos.Location  ();
  const gp_Dir2d& DD = pos.XDirection();
  return gp_Pnt2d (PP.X() + C * DD.X(),
		   PP.Y() + C * DD.Y());
}

 gp_Pnt2d gp_Elips2d::Focus2() const
{
  double C = sqrt (majorRadius * majorRadius -
			  minorRadius * minorRadius);
  const gp_Pnt2d& PP = pos.Location  ();
  const gp_Dir2d& DD = pos.XDirection();
  return gp_Pnt2d (PP.X() - C * DD.X(),
		   PP.Y() - C * DD.Y());
}

 const gp_Pnt2d& gp_Elips2d::Location () const
{ return pos.Location(); }

   double gp_Elips2d::MajorRadius() const
{ return majorRadius; }

   double gp_Elips2d::MinorRadius() const
{ return minorRadius; }

 double gp_Elips2d::Parameter () const
{ 
  if (majorRadius == 0.0) return 0.0;
  else                    return (minorRadius * minorRadius) / majorRadius;
}

   const gp_Ax22d& gp_Elips2d::Axis () const
{ return pos; }

 gp_Ax2d gp_Elips2d::YAxis () const
{  return pos.YAxis(); }

 gp_Ax2d gp_Elips2d::XAxis () const
{   return pos.XAxis();  }

 void gp_Elips2d::Reverse() 
{
  gp_Dir2d Temp = pos.YDirection ();
  Temp.Reverse ();
  pos.SetAxis(gp_Ax22d(pos.Location(),pos.XDirection(),Temp));
}

 gp_Elips2d gp_Elips2d::Reversed() const
{
  gp_Elips2d E = *this;
  gp_Dir2d Temp = pos.YDirection ();
  Temp.Reverse ();
  E.pos.SetAxis(gp_Ax22d(pos.Location(),pos.XDirection(),Temp));
  return E;
}

 bool gp_Elips2d::IsDirect() const
{ return (pos.XDirection().Crossed(pos.YDirection())) >= 0.0; }

 void gp_Elips2d::Rotate (const gp_Pnt2d& P,
				const double Ang)
{ pos.Rotate (P, Ang); }

 gp_Elips2d gp_Elips2d::Rotated (const gp_Pnt2d& P,
				       const double Ang) const  
{
  gp_Elips2d E = *this;
  E.pos.Rotate (P, Ang);
  return E; 
}

 void gp_Elips2d::Scale (const gp_Pnt2d& P,
			       const double S) 
{ 
  majorRadius *= S;
  if (majorRadius < 0) majorRadius = - majorRadius;
  minorRadius *= S;
  if (minorRadius < 0) minorRadius = - minorRadius;
  pos.Scale(P, S);
}

 gp_Elips2d gp_Elips2d::Scaled (const gp_Pnt2d& P,
				      const double S) const  
{
  gp_Elips2d E = *this;
  E.majorRadius *= S;
  if (E.majorRadius < 0) E.majorRadius = - E.majorRadius;
  E.minorRadius *= S;
  if (E.minorRadius < 0) E.minorRadius = - E.minorRadius;
  E.pos.Scale(P, S);
  return E; 
}

 void gp_Elips2d::Transform(const gp_Trsf2d& T)
{
  double TSca = T.ScaleFactor();
  if(TSca<0.0) TSca=-TSca;
  majorRadius *=  TSca;
  minorRadius *=  TSca;
  pos.Transform(T);
}

 gp_Elips2d gp_Elips2d::Transformed (const gp_Trsf2d& T) const  
{
  gp_Elips2d E = *this;
  E.majorRadius *= T.ScaleFactor();
  if (E.majorRadius < 0) E.majorRadius = - E.majorRadius;
  E.minorRadius *= T.ScaleFactor();
  if (E.minorRadius < 0) E.minorRadius = - E.minorRadius;
  E.pos.Transform(T);
  return E;
}

 void gp_Elips2d::Translate (const gp_Vec2d& V)
{ pos.Translate(V); }

 gp_Elips2d gp_Elips2d::Translated (const gp_Vec2d& V) const  
{
  gp_Elips2d E = *this;
  E.pos.Translate(V);
  return E; 
}

 void gp_Elips2d::Translate (const gp_Pnt2d& P1,
				   const gp_Pnt2d& P2) 
{ pos.Translate(P1, P2); }

 gp_Elips2d gp_Elips2d::Translated (const gp_Pnt2d& P1,
					  const gp_Pnt2d& P2) const  
{
  gp_Elips2d E = *this;
  E.pos.Translate(P1, P2);
  return E; 
}

